package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

var xueQiuApiUrlMap = make(map[string]string, 11)

const (
	longHuUrl    string = "https://xueqiu.com/service/v5/stock/hq/longhu"
	stockUrl     string = "https://stock.xueqiu.com/v5/stock/realtime/quotec.json"
	stockListUrl string = "https://xueqiu.com/service/v5/stock/screener/quote/list"
	maxStockNum  int    = 6000 // 股票最大数量(现有股票四千多条，后续这个可以修改)
	longHuTimeH  int    = 16   // 龙虎榜更新时
	longHuTimeM  int    = 30   // 龙虎榜更新分
)

type LongHuItemStruct struct {
	Symbol    string   `json:"symbol"`
	Amount    float32  `json:"amount"`
	Name      string   `json:"name"`
	Close     float32  `json:"close"`
	Percent   float32  `json:"percent"`
	Type_name []string `json:"type_name"`
	Volume    float32  `json:"volume"`
}
type LongHuDataStruct struct {
	Items      []LongHuItemStruct `json:"items"`
	Items_size int                `json:"items_size"`
}
type ResponseDataStruct struct {
	Data              LongHuDataStruct `json:"data"`
	Error_code        int              `json:"error_code"`
	Error_description string           `json:"error_description"`
}

var Db *sqlx.DB

func init() {
	connectMysql()
}

func main() {
	// Todo: 获取这个月的龙虎榜数据，将这个月的数据插入进去
	isBeforeEighteen := checkIsBeforeLongHuTime()
	if isBeforeEighteen {
		fmt.Println("当前时间小于每日执行时间" + strconv.Itoa(longHuTimeH) + ":" + strconv.Itoa(longHuTimeM) + ", 系统将查询是否存在前一天数据, 若存在, 则会更新前一天的数据")
		updateBeforeData(-1)
		return
	} else {
		fmt.Println("当前时间大于每日执行时间" + strconv.Itoa(longHuTimeH) + ":" + strconv.Itoa(longHuTimeM) + ", 系统将插入当日龙虎榜和股票数据")
		addTodayData()
	}
}

// 更新前一天的数据, 没有数据，则会继续找前一天的数据
func updateBeforeData(beforeDay int) {
	yesterDay := time.Now().AddDate(0, 0, beforeDay)
	startTime := time.Date(yesterDay.Year(), yesterDay.Month(), yesterDay.Day(), 0, 0, 0, 0, time.Now().Location())
	startDate := startTime.Format("2006-01-02")
	startTimeStamp := strconv.FormatInt(startTime.UnixNano()/1e6, 10)
	currentTimeStamp := strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
	if result_data, err := getLongHuData(startTimeStamp, currentTimeStamp); err != nil {
		fmt.Println(err)
		os.Exit(1)
	} else {
		fmt.Println("Items_size", result_data.Items_size, startDate)
		items_size := result_data.Items_size
		if beforeDay == -50 {
			os.Exit(1)
		}
		if items_size == 0 {
			beforeDay--
			updateBeforeData(beforeDay)
			os.Exit(1)
		}
		for _, value := range result_data.Items {
			updateLongHuDataSql := "update longhu_list "
			fmt.Println("更新代码为:", value.Symbol, ",名称:", value.Name, "的龙虎榜数据---开始")
			updateLongHuDataSql += fmt.Sprintf("SET amount=%f, close=%f, percent=%f, volume=%f,type_name=%s ", value.Amount, value.Close, value.Percent, value.Volume, value.Type_name)
			updateLongHuDataSql += fmt.Sprintf(" WHERE symbol=%s AND Date=%s", value.Symbol, startDate)
			fmt.Println("更新语句为:", updateLongHuDataSql)
			_, err := Db.Exec(updateLongHuDataSql)
			if err != nil {
				fmt.Println("exec failed, ", err)
				return
			}
			fmt.Println("更新代码为:", value.Symbol, ",名称:", value.Name, "的龙虎榜数据---结束")
		}
	}
}

// 添加当天的龙虎榜
func addTodayData() {
	now := time.Now()
	startTime := time.Date(now.Year(), now.Month(), now.Day(), longHuTimeH, longHuTimeM, 0, 0, time.Now().Location())
	startDate := startTime.Format("2006-01-02")
	startTimeStamp := strconv.FormatInt(startTime.UnixNano()/1e6, 10)
	currentTimeStamp := strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
	if result_data, err := getLongHuData(startTimeStamp, currentTimeStamp); err != nil {
		fmt.Println(err)
		os.Exit(1)
	} else {
		for _, value := range result_data.Items {
			insertLongHuDataSql := "INSERT INTO longhu_list "
			fmt.Println("更新代码为:", value.Symbol, ",名称:", value.Name, "的龙虎榜数据---开始")
			insertLongHuDataSql += fmt.Sprintf("SET amount=%f, close=%f, percent=%f, volume=%f,type_name=%s,symbol=%s,name=%s,Date=%s ", value.Amount, value.Close, value.Percent, value.Volume, value.Type_name, value.Symbol, value.Name, startDate)
			fmt.Println("更新语句为:", insertLongHuDataSql)
			_, err := Db.Exec(insertLongHuDataSql)
			if err != nil {
				fmt.Println("exec failed, ", err)
				return
			}
			fmt.Println("更新代码为:", value.Symbol, ",名称:", value.Name, "的龙虎榜数据---结束")
		}
	}
}

// 获取股票数据  https://stock.xueqiu.com/v5/stock/realtime/quotec.json?symbol=SH000001,SZ399001,SZ399006,SH000688&_=1636523406219
func getStockData(stockCode string, timeStamp string) {
	if timeStamp == "" {
		timeStamp = strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
	}
	if stockCode == "" {
		stockCode = "SH000001"
	}
	url := stockUrl + "?symbol=" + stockCode + "&_=" + timeStamp
	resp, _ := http.Get(url)
	defer resp.Body.Close()

	buf := make([]byte, 1024)

	for {
		// 接受服务器消息
		n, err := resp.Body.Read(buf)
		if err != nil && err != io.EOF {
			fmt.Println(err)
		} else {
			fmt.Println("读取完毕:")
			res := string(buf[:n])
			fmt.Println(res)
			break
		}
	}
}

// 获取龙虎榜数据 https://xueqiu.com/service/v5/stock/hq/longhu?date=1636387200000&_=1636526531819
func getLongHuData(startTimeStamp string, endTimeStamp string) (items LongHuDataStruct, err error) {
	xueQiuApiUrlMap["longHuUrl"] = longHuUrl + "?date=" + startTimeStamp + "&_=" + endTimeStamp
	fmt.Println("请求龙虎榜接口的url为：", xueQiuApiUrlMap["longHuUrl"])
	if result_data, err := httpRequestGet(xueQiuApiUrlMap["longHuUrl"]); err != nil {
		fmt.Println(err)
		return items, err
	} else {
		items = result_data.Data
		return items, err
	}
}

// 获取沪深两市所有代码 https://xueqiu.com/service/v5/stock/screener/quote/list?page=1&size=30&order=desc&orderby=percent&order_by=percent&market=CN&type=sh_sz&_=1636526693905
func getStockList() {
	// now := time.Now()                  // 当前时间
	// currentTimeStamp := now.UnixNano() // 当前时间戳
	// toDaySixTeenClockTimeStamp := time. // 当天下午6点的时间戳
}

func connectMysql() {
	database, err := sqlx.Open("mysql", "root:Ruanchao1993@tcp(124.71.210.127:3306)/stock")
	if err != nil {
		fmt.Println("Open mysql failed:", err)
		return
	}
	Db = database
	defer Db.Close()
}

func insertToStockList() {
	r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu001", "man", "stu01@qq.com")
	if err != nil {
		fmt.Println("exec failed, ", err)
		return
	}
	id, err := r.LastInsertId()
	if err != nil {
		fmt.Println("exec failed,", err)
		return
	}

	fmt.Println("insert succ:", id)
}

type Person struct {
	UserId   int    `db:"user_id"`
	Username string `db:"username"`
	Sex      string `db:"sex"`
	Email    string `db:"email"`
}

func selectDbData() {
	var person []Person
	err := Db.Select(&person, "select user_id, username, sex, email from person where user_id=?", 1)
	if err != nil {
		fmt.Println("exec failed, ", err)
		return
	}

	fmt.Println("select succ:", person)
}

// 检测当前时间是否是18点之前
func checkIsBeforeLongHuTime() bool {
	now := time.Now()
	LongHuTime := time.Date(now.Year(), now.Month(), now.Day(), longHuTimeH, longHuTimeM, 0, 0, now.Location())
	if now.After(LongHuTime) {
		return false
	} else {
		return true
	}
}

// 封装GET请求方法
func httpRequestGet(url string) (data *ResponseDataStruct, err error) {
	var request_b []byte
	if response, err := http.Get(url); err != nil {
		return data, err
	} else {
		if request_b, err = ioutil.ReadAll(response.Body); err != nil {
			return data, err
		}
	}
	data = &ResponseDataStruct{}
	err = json.Unmarshal(request_b, data)
	return data, err
}
